package org.orcas.kocl.compiler.core;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.CollectionType;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
import org.eclipse.ocl.ecore.PrimitiveType;
import org.eclipse.ocl.ecore.SendSignalAction;
import org.eclipse.ocl.expressions.BooleanLiteralExp;
import org.eclipse.ocl.expressions.CollectionItem;
import org.eclipse.ocl.expressions.CollectionKind;
import org.eclipse.ocl.expressions.CollectionLiteralExp;
import org.eclipse.ocl.expressions.EnumLiteralExp;
import org.eclipse.ocl.expressions.IfExp;
import org.eclipse.ocl.expressions.IntegerLiteralExp;
import org.eclipse.ocl.expressions.IterateExp;
import org.eclipse.ocl.expressions.IteratorExp;
import org.eclipse.ocl.expressions.LetExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.OperationCallExp;
import org.eclipse.ocl.expressions.PropertyCallExp;
import org.eclipse.ocl.expressions.RealLiteralExp;
import org.eclipse.ocl.expressions.StringLiteralExp;
import org.eclipse.ocl.expressions.TypeExp;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.expressions.VariableExp;
import org.eclipse.ocl.expressions.impl.VariableExpImpl;
import org.eclipse.ocl.utilities.AbstractVisitor;
import org.eclipse.ocl.utilities.UMLReflection;
import org.orcas.kocl.compiler.util.PredefinedType;
import org.orcas.kocl.compiler.util.StringPool;
import org.orcas.kocl.compiler.util.TemplateUtil;
import org.orcas.kocl.compiler.util.Validator;

public class JavaVisitor<C, O, P, EL, PM, S, COA, SSA, CT> extends 
	AbstractVisitor<String, C, O, P, EL, PM, S, COA, SSA, CT> {
	
	//private final Environment<?, C, O, P, EL, PM, S, COA, SSA, CT, ?, ?> _env;
	private final UMLReflection<?, C, O, P, EL, PM, S, COA, SSA, CT> _uml;
	
	public static JavaVisitor<EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> getEcoreVersion() {
	    
		Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> auxEnv = 
	    	EcoreEnvironmentFactory.INSTANCE.createEnvironment();
	    
		JavaVisitor<EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> res = 
	    	new JavaVisitor<EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint>(auxEnv);
	    return res;
	  }
	
	protected JavaVisitor(Environment<?, C, O, P, EL, PM, S, COA, SSA, CT, ?, ?> env) {
	   // this._env = env;
	    this._uml = (env == null) ? null : env.getUMLReflection();
	}
	
	
	@SuppressWarnings( "serial" )
	@Override
	protected String handleIfExp(IfExp<C> ifExp, final String conditionResult,
		final String thenResult, final String elseResult) {
		
		Map<String, String> map = new HashMap<String, String>(){{
			put("conditionResult", conditionResult);
			put("thenResult", thenResult);
			put("elseResult", elseResult);
		}};
		
		return TemplateUtil.process(PredefinedType.IF_NAME, map);
	}
	
	@SuppressWarnings({ "serial", "unchecked" })
	@Override
	protected String handleOperationCallExp(OperationCallExp<C, O> callExp,
			final String sourceResult, final List<String> argumentResults) {
		
		StringBuilder operationCallBuilder = new StringBuilder();
		
		int opCode = callExp.getOperationCode();
		int numArgs = argumentResults.size();
		
		// source
		OCLExpression<C> source = callExp.getSource();
		final String sourceType = _getName(source.getType());
		
		// arg 0
		final OCLExpression<C> arg0Exp;
		final String arg0Type;  
		final String arg0Result;
		
		// arg 1
		final OCLExpression<C> arg1Exp;
		final String arg1Type;  
		final String arg1Result;
		
		Map<String, String> map = null;
		
		switch (numArgs) {
			case 0:
				
				map = new HashMap<String, String>(){{
					put("sourceResult", sourceResult);
				}};
				
				switch (opCode) {
					case PredefinedType.MINUS:
						map.put("argResult", StringPool.BLANK);
						
						operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.MINUS_NAME, map));
						break;
					case PredefinedType.ABS:
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.ABS_NAME, map));
						break;
					case PredefinedType.FLOOR:
						if (source instanceof RealLiteralExp) {
							//Real::floor()
							operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.FLOOR_NAME, map));
						}
						else {
							//Integer.floor()
							operationCallBuilder.append(sourceResult);
						}
						break;
					case PredefinedType.ROUND:
						if (source instanceof RealLiteralExp) {
							// Real::round()
							operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.ROUND_NAME, map));
						}
						else {
							//Integer::round()
							operationCallBuilder.append(sourceResult);
						}
						break;
					case PredefinedType.NOT:
						map = new HashMap<String, String>(){{
							put("sourceResult", sourceResult);
						}};
						
						operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.NOT_NAME, map));
						break;
					case PredefinedType.OCL_IS_UNDEFINED:
						map = new HashMap<String, String>(){{
							put("sourceResult", sourceResult);
						}};
						
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.OCL_IS_UNDEFINED_NAME, map));
						break;
					case PredefinedType.SIZE:
						
						if (Validator.equals(sourceType, StringPool.STRING)){
							//String::size()
							map.put("operator", "length");	
						} 
						else { 
							//Collection::size()
							map.put("operator", "size");
						}
						
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.SIZE_NAME, map));
						break;
										
					case PredefinedType.TO_INTEGER:
						//String::toInteger()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.TO_INTEGER_NAME, map));
						break;
					case PredefinedType.TO_REAL:
						//Real::toReal()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.TO_REAL_NAME, map));
						break;
					case PredefinedType.TO_LOWER:
						//String::toLower()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.TO_LOWER_NAME, map));
						break;
					case PredefinedType.TO_UPPER:
						//String.toUpper()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.TO_UPPER_NAME, map));
						break;
					case PredefinedType.IS_EMPTY:
						//Collection.isEmpty()
						map = new HashMap<String, String>(){{
							put("sourceResult", sourceResult);
						}};
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.IS_EMPTY_NAME, map));
						break;
					case PredefinedType.NOT_EMPTY:
						//Collection.notEmpty()
						map = new HashMap<String, String>(){{
							put("sourceResult", sourceResult);
						}};
						
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.NOT_EMPTY_NAME, map));
						break;
					case PredefinedType.SUM:
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.SUM_NAME, map));
						break;
					case PredefinedType.FLATTEN:	
						// Set, Bag, Sequence, OrderedSet::flatten()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.FLATTEN_NAME, map));
						break;
					case PredefinedType.AS_SET:
						// Set, Bag, Sequence, OrderedSet::asSet()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.AS_SET_NAME, map));
						break;
					case PredefinedType.AS_BAG:
						// Set, Bag, Sequence, OrderedSet::asSet()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.AS_BAG_NAME, map));
						break;
					case PredefinedType.AS_ORDERED_SET:
						// Set, Bag, Sequence, OrderedSet::asSet()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.AS_ORDERED_SET_NAME, map));
						break;
					case PredefinedType.AS_SEQUENCE:
						// Set, Bag, Sequence, OrderedSet::asSet()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.AS_SEQUENCE_NAME, map));
						break;
					case PredefinedType.FIRST:
						// OrderedSet::first()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.FIRST_NAME, map));
						break;
					case PredefinedType.LAST:
						// OrderedSet::first()
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.LAST_NAME, map));
						break;
					
					case PredefinedType.OCL_IS_INVALID:
						break;
				}
				break;

			case 1:
				
				arg0Exp = callExp.getArgument().get(0);
				arg0Type = _getName(arg0Exp.getType());
				arg0Result = argumentResults.get(0);
				
				map = new HashMap<String, String>(){{
					put("sourceResult", sourceResult);
					put("sourceType", sourceType);
					put("argResult", arg0Result);
					put("argType", arg0Type);
				}};

				switch (opCode) {
					
					case PredefinedType.OCL_IS_TYPE_OF:
						// AnyType::oclIsTypeOf(OclType)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.OCL_IS_TYPE_OF_NAME, map));
						break;
					case PredefinedType.OCL_IS_KIND_OF:
						// AnyType::oclIsKindOf(OclType)
						operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.OCL_IS_KIND_OF_NAME, map));
						break;
					case PredefinedType.OCL_AS_TYPE:
						// AnyType::oclAsType(OclType)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.OCL_AS_TYPE_NAME, map));
						break;
					case PredefinedType.MINUS:
						// Integer::minus(Integer)
						// Real::minus(Real)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.MINUS_NAME, map));
						break;
					case PredefinedType.PLUS:
						// Integer::plus(Integer)
						// Real::plus(Real)
						operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.PLUS_NAME, map));
						break;
					case PredefinedType.MOD:
						// Integer::mod(Integer)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.MOD_NAME, map));
						break;
					case PredefinedType.TIMES:
						// Integer::times(Integer)
						// Real::times(Real)
						operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.TIMES_NAME, map));
						break;
					case PredefinedType.DIVIDE:
						// Integer::divide(Integer)
						// Real::divide(Real)
						operationCallBuilder.append(
								TemplateUtil.process(PredefinedType.DIVIDE_NAME, map));
						break;
					case PredefinedType.DIV:
						// Integer::div(Integer)

						// need to ensure arg must be <> than zero
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.DIV_NAME, map));
						break;
					case PredefinedType.EQUAL:
						//Integer::equal(Integer)
						//Real::equal(Real)
						//String.equal(String)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.EQUAL_NAME, map));
						break;
					case PredefinedType.MIN:
						//Integer::min(Integer)
						//Real::min(Real)
						//Integer::min(Real)
						//Real::min(Integer)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.MIN_NAME, map));
						break;
					case PredefinedType.MAX:
						//Integer::max(Integer)
						//Real::max(Real)
						//Integer::max(Real)
						//Real::max(Integer)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.MAX_NAME, map));
						break;
					case PredefinedType.LESS_THAN:
						//Integer::lessThan(Integer)
						//Real::lessThan(Real)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.LESS_THAN_NAME, map));
						break;
					case PredefinedType.GREATER_THAN:
						//Integer::greaterThan(Integer)
						//Real::greateThan(Real)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.GREATER_THAN_NAME, map));
						break;
					case PredefinedType.LESS_THAN_EQUAL:
						//Integer::lessThanEqual(Integer)
						//Real::lessThanEqual(Real)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.LESS_THAN_EQUAL_NAME, map));
						break;
					case PredefinedType.GREATER_THAN_EQUAL:
						//Integer::greaterThanEqual(Integer)
						//Real::greateThanEqual(Real)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.GREATER_THAN_EQUAL_NAME, map));
						break;
					case PredefinedType.NOT_EQUAL:
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.NOT_EQUAL_NAME, map));
						break;	
					case PredefinedType.AND:
						// Boolean::and(Boolean)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.AND_NAME, map));
						break;
					case PredefinedType.OR:
						// Boolean::or(Boolean)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.OR_NAME, map));
						break;
					case PredefinedType.XOR:
						// Boolean::xor(Boolean)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.XOR_NAME, map));
						break;
					case PredefinedType.IMPLIES:
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.IMPLIES_NAME, map));
						break;
					// Collections Operations	
					case PredefinedType.INCLUDES:
						// Collection::includes(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.INCLUDES_NAME, map));
						break;
					case PredefinedType.INCLUDES_ALL:
						// Collection::includes(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.INCLUDES_ALL_NAME, map));
						break;	
					case PredefinedType.EXCLUDES:
						// Collection::excludes(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.EXCLUDES_NAME, map));
						break;
					case PredefinedType.COUNT:
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.COUNT_NAME, map));
						break;
					// Set Operations
					case PredefinedType.UNION:
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.UNION_NAME, map));
						break;
					case PredefinedType.INTERSECTION:
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.INTERSECTION_NAME, map));
						break;
					case PredefinedType.INCLUDING:
						// Set, Bag, Sequence::including(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.INCLUDING_NAME, map));
						break;
					case PredefinedType.EXCLUDING:
						// Set, Bag, Sequence::excluding(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.EXCLUDING_NAME, map));
						break;
					case PredefinedType.SYMMETRIC_DIFFERENCE:
						// Set::symmetricDifference(Set)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.SYMMETRIC_DIFFERENCE_NAME, map));
						break;
					case PredefinedType.APPEND:
						// OrderedSet, Sequence::append(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.APPEND_NAME, map));

					case PredefinedType.PREPEND:
						// OrderedSet, Sequence::prepend(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.PREPEND_NAME, map));
						break;
					case PredefinedType.AT: 
						// OrderedSet, Sequence::at(Integer)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.AT_NAME, map));
						break;

					case PredefinedType.INDEX_OF:
						// OrderedSet, Sequence::indexOf(T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.INDEX_OF_NAME, map));
						break;
				}
				break;
				
			case 2:
				
				arg0Exp = callExp.getArgument().get(0);
				arg0Type = _getName(arg0Exp.getType());
				arg0Result = argumentResults.get(0);
				
				arg1Exp = callExp.getArgument().get(1);
				arg1Type = _getName(arg1Exp.getType());
				arg1Result = argumentResults.get(1);
				
				map = new HashMap<String, String>(){{
					put("sourceResult", sourceResult);
					put("sourceType", sourceType);
					put("arg0Result", arg0Result);
					put("arg0Type", arg0Type);
					put("arg1Result", arg1Result);
					put("arg1Type", arg1Type);
				}};

				switch (opCode) {
					
					case PredefinedType.INSERT_AT:
						// OrderedSet, Sequence::insertAt(Integer, T)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.INSERT_AT_NAME, map));
					break;
					
					case PredefinedType.SUB_ORDERED_SET:
						// OrderedSet, Sequence::subOrderedSet(Integer, Integer)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.SUB_ORDERED_SET_NAME, map));
					break;
						
					case PredefinedType.SUB_SEQUENCE:
						// OrderedSet, Sequence::subOrderedSet(Integer, Integer)
						operationCallBuilder.append(
							TemplateUtil.process(PredefinedType.SUB_SEQUENCE_NAME, map));
					break;
					
				}
				
				break;
		}
		
		
		return operationCallBuilder.toString();
	}
	
	
	protected String handlePropertyCallExp(PropertyCallExp<C, P> callExp,
			String sourceResult, List<String> qualifierResults) {
		
		StringBuilder propertyCallBuilder = new StringBuilder();
		
		P property = callExp.getReferredProperty();
		String propertyName = _getName(property);
		
		propertyCallBuilder.append(sourceResult);
		propertyCallBuilder.append(StringPool.DOT);
		propertyCallBuilder.append(propertyName);
		
		return propertyCallBuilder.toString();
	}
	
	@SuppressWarnings({ "unchecked", "serial" })
	protected String handleCollectionLiteralExp(
		CollectionLiteralExp<C> literalExp, final List<String> partResults) {
		
		CollectionKind kind = literalExp.getKind();
		String collectionType = _getCollectionType(kind.getValue());
		
		Map map = new HashMap<String, List<String>>(){{
			put("partResults", partResults);
		}};
		
		map.put("type", collectionType);
		
		return TemplateUtil.process("collection", map);
	}
	
	protected String handleCollectionItem(CollectionItem<C> item,
			String itemResult) {
		return itemResult;
	}
	
	@Override
	protected String handleIterateExp(IterateExp<C, PM> callExp,
			String sourceResult, List<String> variableResults,
			String resultResult, String bodyResult) {
		// TODO Auto-generated method stub
		return super.handleIterateExp(callExp, sourceResult, variableResults,
				resultResult, bodyResult);
	}
	
	@SuppressWarnings({ "serial", "unchecked" })
	@Override
	protected String handleIteratorExp(IteratorExp<C, PM> callExp,
			final String sourceResult, final List<String> variableResults, final String bodyResult) {
		
		String expressionName = callExp.getName();
		CollectionLiteralExp source = 
			(CollectionLiteralExp) callExp.getSource();
		List<Variable<C, PM>> variables = callExp.getIterator();
		
		final String sourceType = _getName(source.getType());
		final Variable<C, PM> tmp = variables.get(0);
		final String tmpType = _getVariableType(tmp.getType());

		Variable<C, PM> acc = null;
		
		if (variables.size() > 1){
			acc = variables.get(2);
		}
		
		Map map = new HashMap(){{
			put("sourceType", sourceType);
			put("sourceResult", sourceResult);
			put("variableResults", variableResults);
			put("bodyResult", bodyResult);
			put("tmpName", tmp.getName());
			put("tmpType", tmpType);
		}};
		
		
		if (acc != null){
			map.put("accName", acc.getName());
		}
		
		return TemplateUtil.process(expressionName, map);
	}
	
	@Override
	@SuppressWarnings("serial")
	protected String handleLetExp(LetExp<C, PM> letExp, final String variableResult,
			final String inResult) {
		
		Map<String,String> map = new HashMap<String, String>(){{
			put("variableResult", variableResult);
			put("inResult", inResult);
		}};
		
		return TemplateUtil.process(PredefinedType.LET_NAME, map);
	}
	
	public String visitTypeExp(TypeExp<C> t) {
		C referredType = t.getReferredType();
		return _getName(referredType);
	}
	
	@Override
	protected String handleVariable(Variable<C, PM> variable, String initResult) {
		String variableName = variable.getName();
		String typeName = _getVariableType(variable.getType());

		return typeName + " " + variableName + " = " + initResult+ ";";
	}
		
	public String visitVariableExp(VariableExp<C, PM> v) {
		 Variable<C, PM> vd = v.getReferredVariable();
		 String variableName = vd.getName();
		 
		 if (StringPool.REPLACEMENTS.containsKey(variableName)){
			 return StringPool.REPLACEMENTS.get(variableName);
		 }
		 
		 return variableName;
	}
	
	
	// Primitive Types
	
	@Override
	public String visitRealLiteralExp(RealLiteralExp<C> literalExp) {
		StringBuilder realLiteralBuilder = new StringBuilder();
		realLiteralBuilder.append(StringPool.NEW);
		realLiteralBuilder.append(StringPool.SPACE);
		realLiteralBuilder.append(StringPool.DOUBLE);
		realLiteralBuilder.append(StringPool.OPEN_PARENTHESIS);
		realLiteralBuilder.append(literalExp.getRealSymbol());
		realLiteralBuilder.append(StringPool.CLOSE_PARENTHESIS);
		
		return realLiteralBuilder.toString();
	}
	
	@Override
	public String visitIntegerLiteralExp(IntegerLiteralExp<C> literalExp) {
		StringBuilder integerLiteralBuilder = new StringBuilder();
		integerLiteralBuilder.append(StringPool.NEW);
		integerLiteralBuilder.append(StringPool.SPACE);
		integerLiteralBuilder.append(StringPool.INTEGER);
		integerLiteralBuilder.append(StringPool.OPEN_PARENTHESIS);
		integerLiteralBuilder.append(literalExp.getIntegerSymbol());
		integerLiteralBuilder.append(StringPool.CLOSE_PARENTHESIS);
		
		return integerLiteralBuilder.toString();
	}

	@Override
	public String visitStringLiteralExp(StringLiteralExp<C> literalExp) {
		StringBuilder stringLiteralBuilder = new StringBuilder();
		stringLiteralBuilder.append(StringPool.QUOTES);
		stringLiteralBuilder.append(literalExp.getStringSymbol());
		stringLiteralBuilder.append(StringPool.QUOTES);
		
		return stringLiteralBuilder.toString();
	}
	
	@Override
	public String visitBooleanLiteralExp(BooleanLiteralExp<C> literalExp) {
		StringBuilder booleanLiteralBuilder = new StringBuilder();
		booleanLiteralBuilder.append(StringPool.NEW);
		booleanLiteralBuilder.append(StringPool.SPACE);
		booleanLiteralBuilder.append(StringPool.BOOLEAN);
		booleanLiteralBuilder.append(StringPool.OPEN_PARENTHESIS);
		booleanLiteralBuilder.append(literalExp.getBooleanSymbol());
		booleanLiteralBuilder.append(StringPool.CLOSE_PARENTHESIS);
		
		return booleanLiteralBuilder.toString();
	}
	
	@Override
	public String visitEnumLiteralExp(EnumLiteralExp<C, EL> literalExp) {
		String name = _getName(literalExp.getReferredEnumLiteral());
		return name;
	}
	
	private String _getName(Object named) {
		return (_uml == null) ? StringPool.UNDEFINED : _uml.getName(named); 
	}
	
	private String _getCollectionType(int value){
		switch (value) {
			case CollectionKind.BAG:
				return "org.orcas.commons.collections.bag.HashBag";
			case CollectionKind.SEQUENCE:
				return "org.orcas.commons.collections.list.TreeList";
			case CollectionKind.ORDERED_SET:
				return "org.orcas.commons.collections.set.LinkedHashSet";
			default: //Set
				return "org.orcas.commons.collections.set.HashSet";
		}
	}
	
	private String _getVariableType(C type){
		if (type instanceof CollectionType){
			return _getCollectionType(((CollectionType) type).getKind().getValue());
		}
		else {
			return _getName(type);
		}
	}
}